package com.yyfax.pay.quartz.service.impl;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.yyfax.commons.http.HttpUtil;
import com.yyfax.commons.json.JacksonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.model.EmptyContent;
import com.yyfax.pay.common.constants.QuartzConstant;
import com.yyfax.pay.common.enums.TaskStateEnum;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.to.YYPayRsp;
import com.yyfax.pay.depository.dao.FuiouNotifyTaskDao;
import com.yyfax.pay.depository.domain.FuiouNotifyTask;
import com.yyfax.pay.quartz.service.FuiouDepositNotifyService;

@Service
public class FuiouDepositNotifyServiceImpl implements FuiouDepositNotifyService {

	private static final Logger logger = LoggerFactory.getLogger(FuiouDepositNotifyServiceImpl.class);

	@Resource
	private FuiouNotifyTaskDao fuiouNotifyTaskDao;

	@Resource
	private QuartzConstant quartzConstant;

	@Override
	public void executeTask(FuiouNotifyTask task) {
		final String op = "FuiouDepositNotifyServiceImpl.handle";
		Exception jobException = null;
		boolean isSuccess = false;
		
		logger.info(Log.op(op).msg("【富友存管】【异步通知业务】开始执行").kv("FuiouNotifyTask", task).toString());
		
		try {
			try {
				task.setOptNo(task.getOptNo() + 1);
				isSuccess = doPost(task);
			} catch (Exception e) {
				logger.error(Log.op(op).msg("【富友存管】【异步通知业务】执行异常").kv("FuiouNotifyTask", task).toString(), e);
				jobException = e;
			}

			proccessResult(task, isSuccess, jobException);
		} catch (Exception e) {
			logger.error(Log.op(op).msg("执行富友存管异步通知任务未知异常").kv("FuiouNotifyTask", task).toString(), e);
		}
	}

	/**
	 * 判断任务是否可执行
	 * 
	 * @author buyi
	 * @date 2017-09-21 11:41:49
	 * @since v2.0.0
	 * @param task
	 * @return false-表示不可执行；true-表示可执行
	 */
	private boolean isExecute(FuiouNotifyTask task) {
		final String op = "FuiouDepositNotifyServiceImpl.isExecute";
		if (task == null) {
			return false;
		}

		if (!TaskStateEnum.ACTIVE.isValue(task.getState())) {
			logger.info(Log.op(op).msg("富友存管异步通知业务方,状态非激活状态，不执行").kv("FuiouNotifyTask", task).toString());
			return false;
		}

		if (task.getOptNo() >= task.getMaxNo()) {
			logger.info(Log.op(op).msg("富友存管异步通知业务方,通知次数已经达到最大执行次数，不执行").kv("FuiouNotifyTask", task).toString());
			return false;
		}

		if (task.getEndTime() != null && task.getEndTime().compareTo(DateUtil.getCurrentDateTime()) <= 0) {
			logger.info(Log.op(op).msg("富友存管异步通知业务方,已经过期，不执行").kv("FuiouNotifyTask", task).toString());
			return false;
		}

		return true;
	}

	/**
	 * 发送请求
	 * 
	 * @author buyi
	 * @date 2017-09-04 11:27:36
	 * @since v2.0.0
	 * @param task
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	private boolean doPost(FuiouNotifyTask task) throws IOException {
		String op = "FuiouDepositNotifyServiceImpl.doPost";
		try {

			Map<String, String> header = null;

			if (StringUtils.isNotBlank(task.getReqHeader())) {
				// 如果请求头部，不为空，则转换
				header = JSON.parseObject(task.getReqHeader(), Map.class);
			}

			// 发送请求
			String rspJson = HttpUtil.postBodyDirect(task.getReqUrl(), task.getReqContent(), header, null, null, null, null,
					quartzConstant.getNotifyConnectTimeout(), quartzConstant.getNotifyReadTimeout());

			logger.info(Log.op(op).msg("富友存管异步通知业务方，响应").kv("FuiouNotifyTask", task).kv("响应报文", rspJson).toString());

			if (StringUtils.isBlank(rspJson)) {
				return false;
			}

			YYPayRsp<EmptyContent> rsp = JacksonUtil.fromJson(rspJson, YYPayRsp.class, EmptyContent.class);
			if (rsp == null) {
				return false;
			}

			if (PayExceptionCode.SUCCESS.isCode(rsp.getCode())) {
				// 只有响应成功状态，才返回成功
				return true;
			}
		} catch (SocketTimeoutException e) {
			logger.error(Log.op(op).msg("富友存管异步通知业务方，请求超时").kv("FuiouNotifyTask", task).toString());
		}

		return false;
	}

	/**
	 * 处理执行结果<br>
	 * 包含
	 * 
	 * @author buyi
	 * @date 2017-09-04 11:22:48
	 * @since v2.0.0
	 * @param task
	 * @param isSuccess
	 * @param jobException
	 */
	private void proccessResult(FuiouNotifyTask task, boolean isSuccess, Exception exception) {
		if (task == null) {
			logger.warn("proccess result is ill task is null");
			return;
		}

		processTask(task, isSuccess, exception);

		// 更新任务状态
		fuiouNotifyTaskDao.updateByPrimaryKeySelective(task);
	}

	/**
	 * 处理任务信息<br>
	 * 包含成功或者失败，以及下一次调度机制
	 * 
	 * @author buyi
	 * @date 2017-09-04 14:18:15
	 * @since v2.0.0
	 * @param task
	 * @param isSuccess
	 * @param exception
	 */
	private void processTask(FuiouNotifyTask task, boolean isSuccess, Exception exception) {
		// 计算下一次执行时间
		task.setNextTime(quartzConstant.getNotifyNextTime(task.getOptNo() - 1));
		// 更新最后一次执行时间
		task.setLastTime(DateUtil.getCurrentDateTime());

		if (exception != null) {
			// 如果异常，则更新任务为失败
			task.setState(isExecute(task) ? TaskStateEnum.ACTIVE.getValue() : TaskStateEnum.FAILED.getValue());
			task.setRemark(exception.getMessage());

			return;
		}

		if (isSuccess) {
			task.setState(TaskStateEnum.SUCCESS.getValue());
			task.setRemark(TaskStateEnum.SUCCESS.getRemark());
			return;
		}

		if (!isExecute(task)) {
			// 如果超过最大的执行次数，或者 当期时间已经超过结束时间，则任务失败
			task.setState(TaskStateEnum.FAILED.getValue());
			task.setRemark("达到最大执行次数，或者已经过期");
			return;
		}

		// 其他情况，则任务为激活状态，等待下一次调度
		task.setState(TaskStateEnum.ACTIVE.getValue());
	}

}
